gdkdnd: Add private means to commit the drag status
authorCarlos Garnacho <carlosg@gnome.org>
Wed, 9 Mar 2016 16:00:31 +0000 (17:00 +0100)
committerCarlos Garnacho <carlosg@gnome.org>
Mon, 14 Mar 2016 15:50:36 +0000 (16:50 +0100)
The way gdk_drag_status() may be called multiple times during the
processing of drag and drop events throughout the widget hierarchy
brings some superfluous messaging going in, esp. when it's the last
request the one we want to honor, yet we emit messaging requests on
all.

This is barely appreciable in the X11 backend, but due to the design
of the wayland protocol, quick series of changes like this it have
some self-amplificating consequences which may end up flooding the
connection.

We can delegate this to a late "commit" call, performed within GDK
event management. This way gdk_drag_status() calls may be cached
and only result in windowing messaging once per ::drag-motion or
::drag-data-received event. Emitting the final status will also
avoid spurious action changes on the compositor and the other peer.

https://bugzilla.gnome.org/show_bug.cgi?id=763298

gdk/gdkdnd.c
gdk/gdkdndprivate.h
gdk/gdkevents.c
gdk/wayland/gdkdnd-wayland.c

index 02d8d53420a797ac619477852deef914873ee53f..3cbd5312cac96f0b7ccdc11a2d9e6db9c9fbcaea 100644 (file)
@@ -764,3 +764,53 @@ gdk_drag_get_cursor (GdkDragAction action)
                                                        drag_cursors[i].name);
   return drag_cursors[i].cursor;
 }
+
+static void
+gdk_drag_context_commit_drag_status (GdkDragContext *context)
+{
+  GdkDragContextClass *context_class;
+
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (!context->is_source);
+
+  context_class = GDK_DRAG_CONTEXT_GET_CLASS (context);
+
+  if (context_class->commit_drag_status)
+    context_class->commit_drag_status (context);
+}
+
+gboolean
+gdk_drag_context_handle_dest_event (GdkEvent *event)
+{
+  GdkDragContext *context = NULL;
+  GList *l;
+
+  switch (event->type)
+    {
+    case GDK_DRAG_MOTION:
+    case GDK_DROP_START:
+      context = event->dnd.context;
+      break;
+    case GDK_SELECTION_NOTIFY:
+      for (l = contexts; l; l = l->next)
+        {
+          GdkDragContext *c = l->data;
+
+          if (!c->is_source &&
+              event->selection.selection == gdk_drag_get_selection (c))
+            {
+              context = c;
+              break;
+            }
+        }
+      break;
+    default:
+      return FALSE;
+    }
+
+  if (!context)
+    return FALSE;
+
+  gdk_drag_context_commit_drag_status (context);
+  return TRUE;;
+}
index c66de32d850b2fc0c774398ab5bc5bd582054486..283dba2b85430881a68d7afcc7958b509d560483 100644 (file)
@@ -84,6 +84,8 @@ struct _GdkDragContextClass {
                                  const GdkEvent  *event);
   void        (*action_changed) (GdkDragContext  *context,
                                  GdkDragAction    action);
+
+  void        (*commit_drag_status) (GdkDragContext  *context);
 };
 
 struct _GdkDragContext {
@@ -116,6 +118,7 @@ void     gdk_drag_context_set_cursor          (GdkDragContext *context,
 void     gdk_drag_context_cancel              (GdkDragContext      *context,
                                                GdkDragCancelReason  reason);
 gboolean gdk_drag_context_handle_source_event (GdkEvent *event);
+gboolean gdk_drag_context_handle_dest_event   (GdkEvent *event);
 GdkCursor * gdk_drag_get_cursor (GdkDragAction action);
 
 G_END_DECLS
index 6a6771cf0aed90b15233dcc8a522261ab77db09f..2eb249e7760e3030829b9ce8fc322593ed0ba4eb 100644 (file)
@@ -71,6 +71,9 @@ _gdk_event_emit (GdkEvent *event)
 
   if (_gdk_event_func)
     (*_gdk_event_func) (event, _gdk_event_data);
+
+  if (gdk_drag_context_handle_dest_event (event))
+    return;
 }
 
 /*********************************************
index 1d71d90f342f16176b67cbb4ccfd1b9625664c7c..2a2bad51e63e38393f87550bb7fa2057ed1381a0 100644 (file)
@@ -287,8 +287,6 @@ gdk_wayland_drag_context_drag_status (GdkDragContext *context,
 
   wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
   wayland_context->selected_action = action;
-
-  gdk_wayland_drag_context_commit_status (context);
 }
 
 static void
@@ -471,6 +469,7 @@ gdk_wayland_drag_context_class_init (GdkWaylandDragContextClass *klass)
   context_class->action_changed = gdk_wayland_drag_context_action_changed;
   context_class->drop_performed = gdk_wayland_drag_context_drop_performed;
   context_class->cancel = gdk_wayland_drag_context_cancel;
+  context_class->commit_drag_status = gdk_wayland_drag_context_commit_status;
 }
 
 GdkDragProtocol